#ifndef __A51_CUDA__
#define __A51_CUDA__

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <map>
#include <deque>
#include <queue>

#include <boost/thread/thread.hpp>

#include "Advance.h"

using namespace std;

class A51CudaSlice;

class A51Cuda
{
    public:
        A51Cuda(uint32_t maxRounds, int condition);
        ~A51Cuda();

        int Submit(uint64_t start_value, unsigned int start_round, uint32_t advance, void* context);
        int SubmitPartial(uint64_t start_value, unsigned int stop_round, uint32_t advance, void* context);
        bool PopResult(uint64_t&, uint64_t&);
        typedef struct {
            uint64_t start_value;
            uint64_t end_value;
            int start_round;
            int end_round;
            const uint64_t* round_func;
            void* context;
            unsigned int current_round;
            unsigned int cycles;
            bool idle;
        } JobPiece_s;

    private:
        friend class A51CudaSlice;
        /* multithreading */
        bool mRunning;
        boost::mutex mMutex;
        boost::thread* processThread;

        /* queue info */
        unsigned int mCondition;
        unsigned int mMaxRound;

        /* input queues */
        deque<uint64_t> mInputStart;
        deque<unsigned int> mInputRoundStart;
        deque<unsigned int> mInputRoundStop;
        deque<void*>    mInputContext;
        deque<uint32_t> mInputAdvance;

        /* output queues */
        queue< pair<uint64_t,uint64_t> > mOutput;
        queue<unsigned int> mOutputStartRound;
        queue<unsigned int> mOutputStopRound;
        queue<void*> mOutputContext;

        bool PushResult(JobPiece_s*);
        bool PopRequest(JobPiece_s*);
        map< uint32_t, class Advance* > mAdvanceMap;

        void Process();

};

#endif
